package com.demo.crm.controller;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.arvato.crm.common.DynamicQueryUtil;
import com.arvato.crm.common.ValidErrorUtil;
import com.arvato.crm.model.FilterRule;
import com.arvato.crm.model.PagingInfo;
import com.arvato.crm.service.CrudFactory;
import com.arvato.crm.service.CrudService;
import com.demo.crm.model.AjaxInfo;
import com.uaihebert.uaicriteria.UaiCriteria;

/**
 * 动态增删改查控制
 *
 * @author tanshuai
 */
@Controller
@RequestMapping
@Slf4j
public class CrudController {

    @Autowired
    private Validator validator;

    @RequestMapping("/{name}/edit")
    @ResponseBody
    @Transactional
    public AjaxInfo edit(@PathVariable String name, @RequestParam(required = false) String id, HttpServletRequest request) {
        CrudService service = CrudFactory.create(name);
        Object entity = service.createEntity();
        if (entity == null) {
            return AjaxInfo.EXCEPTION;
        }

        ServletRequestDataBinder binder = new ServletRequestDataBinder(entity);
        if (StringUtils.isEmpty(id)) {
            binder.setDisallowedFields("id");
        }
        binder.setValidator(validator);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
        binder.bind(request);
        binder.validate();

        Errors errors = binder.getBindingResult();
        if (errors.hasErrors()) {
            return new AjaxInfo(false, ValidErrorUtil.toString(errors));
        }

        if (StringUtils.isEmpty(id) || StringUtils.equals(id, "0")) {
            service.save(entity);
        } else {
            service.edit(entity, id);
        }
        return AjaxInfo.SUCCESS;
    }

    @RequestMapping("/{name}/toEdit/{id}")
    public String toEdit(@PathVariable String name, @PathVariable String id, String targetUrl, HttpServletRequest request) {
        request.setAttribute("entity", CrudFactory.create(name).findById(id));
        return targetUrl;
    }
    
    @RequestMapping("/{name}/toEditByFk/{fk}/{id}")
    public String toEditByFk(@PathVariable String name, @PathVariable String fk,@PathVariable String id, String targetUrl, HttpServletRequest request) {
    	PagingInfo pagingInfo = new PagingInfo();
    	pagingInfo.addRule(new FilterRule(fk, id));
    	List result = CrudFactory.create(name).queryList(pagingInfo);
    	request.setAttribute("fkId", id);
    	request.setAttribute("entity", result.isEmpty()?null:result.get(0));
    	return targetUrl;
    }

    @RequestMapping("/{name}/remove/{id}")
    @ResponseBody
    @Transactional
    public AjaxInfo remove(@PathVariable String name, @PathVariable String id) {
        CrudFactory.create(name).remove(id);
        return AjaxInfo.SUCCESS;
    }

    @RequestMapping("/{name}/detail/{id}")
    @ResponseBody
    public Object findById(@PathVariable String name, @PathVariable String id) {
        return CrudFactory.create(name).findById(id);
    }
    
    @RequestMapping("/{name}/child/{pname}/{pid}")
    @ResponseBody
    public Object findChildByPId(@PathVariable String name, @PathVariable String pname, @PathVariable String pid) {
    	return CrudFactory.create(name).findChildByPId(pname, pid);
    }

    @RequestMapping("/{name}/findOne")
    @ResponseBody
    public Object findOne(@PathVariable String name, PagingInfo pagingInfo) {
        return CrudFactory.create(name).findOne(pagingInfo);
    }

    @RequestMapping("/{name}/list")
    @ResponseBody
    public List list(@PathVariable String name, PagingInfo pagingInfo) {
        return CrudFactory.create(name).queryList(pagingInfo);
    }
    
//	@RequestMapping("/{name}/export")
//	public String export(@PathVariable String name, PagingInfo pagingInfo, ModelMap map) {
//
//		map.put(ExportExcelView.FILE_NAME, name);
//		map.put(ExportExcelView.CLASS, CrudFactory.getClassByName(name));
//		map.put(ExportExcelView.DATA_LIST, CrudFactory.create(name).queryList(pagingInfo));
//		return ExportExcelView.VIEW_NAME;
//	}

    @RequestMapping("/{name}/paging")
    @ResponseBody
    public Map paging(@PathVariable String name, PagingInfo pagingInfo) {
        return CrudFactory.create(name).paging(pagingInfo);
    }
    
    @RequestMapping("/{name}/delete")
    @ResponseBody
    @Transactional
    public AjaxInfo delete(@PathVariable String name, String idStr) {
        String[] ids = StringUtils.split(idStr, ",");
        for (String id : ids) {
            remove(name, id);
        }
        return AjaxInfo.SUCCESS;
    }
    
    
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@RequestMapping(value = "/{name}/typeaheadQuery")
	@ResponseBody
	public List typeaheadQuery(@PathVariable String name, @RequestParam("query") String query, @RequestParam(value = "ids", required = false) String ids,
			@RequestParam(value = "fields", required = false) String fields) {
		UaiCriteria criteria = DynamicQueryUtil.getCriteria(CrudFactory.create(name).getEntityClass());
		if("".equals(StringUtils.trimToEmpty(query))) {
			criteria.andAttributeIn("id", Arrays.asList(ids.split(",")));
		} else {
			for(String field : StringUtils.split(fields, ",")){
				criteria.orStringLike(field, "%" + query + "%");
			}
		}
		return criteria.setMaxResults(10).getResultList();
	}
}
